package com.nice.rm.event;

import java.util.concurrent.BlockingQueue;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.LinkedBlockingQueue;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class EventDispatcher implements Runnable {

    private static final Logger log = LoggerFactory.getLogger(EventDispatcher.class);
    private static final EventDispatcher INSTANCE = new EventDispatcher();

    private ExecutorService service;
    private volatile boolean isRunnnig;
    private BlockingQueue<Event> events;
    private CopyOnWriteArrayList<EventHandler> handlers;

    public static EventDispatcher getInstance() {
	return INSTANCE;
    }

    private EventDispatcher() {
	service = Executors.newCachedThreadPool();
	events = new LinkedBlockingQueue<Event>();
	handlers = new CopyOnWriteArrayList<EventHandler>();
    }

    public boolean regist(EventHandler handler) {
	return handlers.add(handler);
    }

    public void shutdown() {
	service.shutdownNow();
	isRunnnig = false;
    }

    public boolean sendEvent(Event event) {
	return events.add(event);
    }

    public void startEventLoop() {
	if (isRunnnig)
	    return;
	isRunnnig = true;
	service.execute(this);
    }

    protected void dispatchEvent(Event event) {
	for (EventHandler hd : handlers) {
	    try {
		if (hd.match(event.type)) {
		    hd.handle(event);
		}
	    } catch (Exception e) {
		log.error("call event handler error:" + hd, e);
	    }
	}
    }

    @Override
    public void run() {
	Thread.currentThread().setName("event-dispatch");
	while (!Thread.interrupted()) {
	    try {
		dispatchEvent(events.take());
	    } catch (Exception e) {
		log.error("dispatch event error", e);
	    }
	}
    }
}
